package com.r2coding.server.common.aspect;

import com.r2coding.cache.core.constants.CacheConstants;
import com.r2coding.core.response.ResponseCode;
import com.r2coding.core.response.Result;
import com.r2coding.core.utils.JwtUtil;
import com.r2coding.server.common.annotation.LoginIgnore;
import com.r2coding.server.common.utils.UserIdUtil;
import com.r2coding.server.modules.user.constants.UserConstants;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Objects;

/**
 * @author 98k灬
 * @version v1.0.0
 * @Description : 功能描述
 * @Create on : 2023/10/8 13:31
 **/
@Component
@Aspect
@Slf4j
public class CommonLoginAspect {
    /**
     * 登录认证参数名称
     */
    private static final String LOGIN_AUTH_PARAM_NAME = "authorization";

    /**
     * 请求头登录认证key
     */
    private static final String LOGIN_AUTH_REQUEST_HEADER_NAME = "Authorization";

    /**
     * 切点表达式
     */
    private static final String POINT_CUT = "execution(* com.r2coding.server.modules.*.controller..*(..))";

    @Autowired
    private CacheManager cacheManager;

    @Pointcut(value = POINT_CUT)
    public void loginAuth() {

    }

    @Around("loginAuth()")
    public Object loginAuthAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        if (this.checkNeedCheckLoginInfo(proceedingJoinPoint)) {
            ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = servletRequestAttributes.getRequest();
            String uri = request.getRequestURI();
            log.info("成功拦截到请求， URI为：[{}]", uri);
            if (!checkAndSaveUserId(request)) {
                log.warn("成功拦截到请求， URI为：[{}], 检测到用户未登录，将跳转到登录页面", uri);
                return Result.error(ResponseCode.NEED_LOGIN);
            }
        }
        return proceedingJoinPoint.proceed();
    }

    private boolean checkAndSaveUserId(HttpServletRequest request) {
        String token = request.getHeader(LOGIN_AUTH_REQUEST_HEADER_NAME);
        if (StringUtils.isBlank(token)) {
            token = request.getParameter(LOGIN_AUTH_PARAM_NAME);
        }

        if (StringUtils.isBlank(token)) {
            return false;
        }

        Object userId = JwtUtil.analyzeToken(token, UserConstants.LOGIN_USER_ID);
        if (Objects.isNull(userId)) {
            return false;
        }

        Cache cache = cacheManager.getCache(CacheConstants.CACHE_NAME);
        String redisToken = cache.get(UserConstants.USER_LOGIN_PREFIX + userId, String.class);
        if (StringUtils.isBlank(redisToken)) {
            return false;
        }

        if (Objects.equals(token, redisToken)) {
            saveUserId(userId);
            return true;
        }

        return false;
    }

    private void saveUserId(Object userId) {
        UserIdUtil.set(Long.valueOf(String.valueOf(userId)));
    }

    private boolean checkNeedCheckLoginInfo(ProceedingJoinPoint proceedingJoinPoint) {
        Signature signature = proceedingJoinPoint.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        Method method = methodSignature.getMethod();
        return !method.isAnnotationPresent(LoginIgnore.class);
    }
}
